package com.duojuhe.coremodule.system.service.impl;

import com.duojuhe.cache.LoginUserTokenCache;
import com.duojuhe.cache.SystemDictCache;
import com.duojuhe.common.annotation.KeyLock;
import com.duojuhe.common.bean.UserTokenInfoVo;
import com.duojuhe.common.constant.SystemConstants;
import com.duojuhe.common.enums.SystemEnum;
import com.duojuhe.common.enums.user.UserEnum;
import com.duojuhe.common.exception.base.DuoJuHeException;
import com.duojuhe.common.result.ErrorCodes;
import com.duojuhe.common.result.PageResult;
import com.duojuhe.common.result.ServiceResult;
import com.duojuhe.common.utils.encryption.md5.MD5Util;
import com.duojuhe.common.utils.encryption.sm4.Sm4Util;
import com.duojuhe.common.utils.idgenerator.UUIDUtils;
import com.duojuhe.common.utils.page.PageHelperUtil;
import com.duojuhe.coremodule.BaseService;
import com.duojuhe.coremodule.system.entity.*;
import com.duojuhe.coremodule.system.mapper.*;
import com.duojuhe.coremodule.system.pojo.dto.tenant.*;
import com.duojuhe.coremodule.system.service.SystemTenantService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class SystemTenantServiceImpl  extends BaseService implements SystemTenantService {
    @Resource
    private LoginUserTokenCache loginUserTokenCache;
    @Resource
    private SystemDictCache systemDictCache;
    @Resource
    private SystemTenantMapper systemTenantMapper;
    @Resource
    private SystemDeptMapper systemDeptMapper;
    @Resource
    private SystemUserMapper systemUserMapper;
    @Resource
    private SystemRoleMenuMapper systemRoleMenuMapper;
    @Resource
    private SystemMenuMapper systemMenuMapper;
    @Resource
    private SystemTenantMenuMapper systemTenantMenuMapper;

    /**
     * 【分页查询】分页查询租户list
     * @param req
     * @return
     */
    @Override
    public ServiceResult<PageResult<List<QuerySystemTenantPageRes>>> querySystemTenantPageResList(QuerySystemTenantPageReq req) {
        PageHelperUtil.orderByAndStartPage(req, "createTime desc, tenantId desc");
        List<QuerySystemTenantPageRes> list = systemTenantMapper.querySystemTenantPageResList(req);
        list.forEach(this::setHandleSystemTenantDictNameColor);
        return PageHelperUtil.returnServiceResult(req,list);
    }

    /**
     * 【保存】租户信息
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult saveSystemTenant(SaveSystemTenantReq req) {
        //校验租户名称是否重复
        isExistTenantName(req.getTenantName());
        //检查登录名是否存在
        isExistUserLoginName(req.getLoginName());
        //校验手机号码是否已经存在
        isExistUserMobileNumber(req.getMobileNumber());
        //当前登录人人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //当前时间
        Date nowDate = new Date();
        //租户ID
        String tenantId = UUIDUtils.getUUID32();
        //租户名称
        String tenantName = req.getTenantName();
        //租户编号
        String tenantNumber = UUIDUtils.getSequenceNo();
        //添加租户
        SystemTenant systemTenant = new SystemTenant();
        systemTenant.setTenantId(tenantId);
        systemTenant.setTenantName(tenantName);
        systemTenant.setTenantAbbreviation(req.getTenantAbbreviation());
        systemTenant.setTenantNumber(tenantNumber);
        systemTenant.setStatusCode(SystemEnum.STATUS.NORMAL.getKey());
        systemTenant.setCreateTime(nowDate);
        systemTenant.setUpdateTime(nowDate);
        systemTenant.setCreateUserId(userTokenInfoVo.getUserId());
        systemTenant.setUpdateUserId(userTokenInfoVo.getUserId());
        systemTenant.setBuiltIn(SystemEnum.YES_NO.NO.getKey());
        //非常重要，不可修改，否则加密文件无法解密回来
        systemTenant.setSm4Key(Sm4Util.generateKeyString());
        systemTenantMapper.insertSelective(systemTenant);
        //添加部门
        SystemDept systemDept = new SystemDept();
        systemDept.setDeptId(tenantId);
        systemDept.setDeptName(tenantName);
        systemDept.setDeptCode(UUIDUtils.getSequenceNo());
        systemDept.setDeptLeader(req.getTenantAbbreviation());
        systemDept.setParentId(SystemConstants.UNKNOWN_ID);
        systemDept.setDeptPath("/" + tenantId);
        systemDept.setDeptTelephone(req.getMobileNumber());
        systemDept.setCreateTime(nowDate);
        systemDept.setUpdateTime(nowDate);
        systemDept.setBuiltIn(SystemEnum.YES_NO.YES.getKey());
        systemDept.setCreateUserId(userTokenInfoVo.getUserId());
        systemDept.setUpdateUserId(userTokenInfoVo.getUserId());
        systemDept.setCreateDeptId(tenantId);
        systemDept.setTenantId(tenantId);
        systemDept.setSort(0);
        systemDept.setRemark("");
        systemDept.setDeptFax("");
        systemDeptMapper.insertSelective(systemDept);
        //添加用户
        String newPwd = MD5Util.getMD532(MD5Util.getMD532(req.getPassword()));
        SystemUser systemUser = new SystemUser();
        systemUser.setUserId(tenantId);
        systemUser.setUserNumber(UUIDUtils.getSequenceNo());
        systemUser.setLoginName(req.getLoginName());
        systemUser.setMobileNumber(req.getMobileNumber());
        systemUser.setCreateDeptId(tenantId);
        systemUser.setTenantId(tenantId);
        systemUser.setStatusCode(SystemEnum.STATUS.NORMAL.getKey());
        systemUser.setPassword(newPwd);
        systemUser.setRealName(req.getTenantAbbreviation());
        systemUser.setModuleCode(SystemEnum.MODULE.TENANT_MODULE.getKey());
        systemUser.setUserTypeCode(UserEnum.USER_TYPE.TENANT_ADMIN.getKey());
        systemUser.setCreateUserId(userTokenInfoVo.getUserId());
        systemUser.setUpdateUserId(userTokenInfoVo.getUserId());
        systemUser.setCreateTime(nowDate);
        systemUser.setUpdateTime(nowDate);
        systemUser.setRoleId("");
        systemUser.setPostId("");
        systemUser.setGenderCode("");
        systemUserMapper.insertSelective(systemUser);
        //插入租户功能菜单
        batchInsertSystemTenantMenuList(tenantId,req.getMenuIdList());
        return ServiceResult.ok(tenantId);
    }



    /**
     * 【修改】租户信息
     * @param req
     * @return
     */
    @KeyLock(lockKeyParts = "tenantId")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult updateSystemTenant(UpdateSystemTenantReq req) {
        //租户ID
        String tenantId = req.getTenantId();
        //查询租户
        SystemTenant systemTenantOld = systemTenantMapper.selectByPrimaryKey(tenantId);
        if (systemTenantOld==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        if (!SystemEnum.YES_NO.NO.getKey().equals(systemTenantOld.getBuiltIn())){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //查询租户的登录账号
        SystemUser systemUserOld = systemUserMapper.selectByPrimaryKey(tenantId);
        if (systemUserOld==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //校验租户名称是否重复
        if (!systemTenantOld.getTenantName().equals(req.getTenantName())){
            isExistTenantName(req.getTenantName());
        }
        //校验手机号码是否已经存在
        if (!systemUserOld.getMobileNumber().equals(req.getMobileNumber())){
            isExistUserMobileNumber(req.getMobileNumber());
        }
        //当前登录人人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //当前时间
        Date nowDate = new Date();
        //租户名称
        String tenantName = req.getTenantName();
        //修改租户
        SystemTenant systemTenant = new SystemTenant();
        systemTenant.setTenantId(req.getTenantId());
        systemTenant.setTenantName(tenantName);
        systemTenant.setTenantAbbreviation(req.getTenantAbbreviation());
        systemTenant.setUpdateTime(nowDate);
        systemTenant.setUpdateUserId(userTokenInfoVo.getUserId());
        systemTenantMapper.updateByPrimaryKeySelective(systemTenant);

        //修改租户的管理账号
        SystemUser systemUser = new SystemUser();
        systemUser.setUserId(systemUserOld.getUserId());
        systemUser.setMobileNumber(req.getMobileNumber());
        systemUser.setUpdateTime(nowDate);
        systemUser.setUpdateUserId(userTokenInfoVo.getUserId());
        systemUserMapper.updateByPrimaryKeySelective(systemUser);
        //插入租户功能菜单
        batchInsertSystemTenantMenuList(tenantId,req.getMenuIdList());
        //租户信息发送变化了，所有子账号需要重新登录
        loginUserTokenCache.kickOutOnlineUserByTenantId(tenantId);
        return ServiceResult.ok(tenantId);
    }

    /**
     * 【改变状态】根据租户id改变租户状态
     * @param req
     * @return
     */
    @KeyLock(lockKeyParts = "tenantId")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult updateSystemTenantStatusByTenantId(SystemTenantIdReq req) {
        //租户id
        String tenantId = req.getTenantId();
        //查询租户
        SystemTenant systemTenantOld = systemTenantMapper.selectByPrimaryKey(tenantId);
        if (systemTenantOld==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        if (!SystemEnum.YES_NO.NO.getKey().equals(systemTenantOld.getBuiltIn())){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //默认用户状态
        String status = SystemEnum.STATUS.FORBID.getKey();
        if (status.equals(systemTenantOld.getStatusCode())){
            status = SystemEnum.STATUS.NORMAL.getKey();
        }
        SystemTenant systemTenant = new SystemTenant();
        systemTenant.setTenantId(tenantId);
        systemTenant.setStatusCode(status);
        systemTenant.setUpdateTime(new Date());
        systemTenant.setUpdateUserId(getCurrentLoginUserId());
        systemTenantMapper.updateByPrimaryKeySelective(systemTenant);
        //租户状态被禁用了，强制踢出该租户下所有用户的所有在线会话
        if (status.equals(SystemEnum.STATUS.FORBID.getKey())){
            loginUserTokenCache.kickOutOnlineUserByTenantId(tenantId);
        }
        return ServiceResult.ok(tenantId);
    }

    /**
     * 【租户绑定菜单-渲染租户绑定菜单】查询TenantId对应的菜单权限集合
     * @param req
     * @return
     */
    @Override
    public ServiceResult<List<String>> querySystemMenuIdListByTenantId(SystemTenantIdReq req) {
        //租户id
        String tenantId = req.getTenantId();
        //查询租户
        SystemTenant systemTenantOld = systemTenantMapper.selectByPrimaryKey(tenantId);
        if (systemTenantOld==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        return ServiceResult.ok(systemTenantMenuMapper.querySystemMenuIdListByTenantId(tenantId));
    }

    /**
     * 【重置密码】根据租户用户id重置密码
     * @param req
     * @return
     */
    @KeyLock(lockKeyParts = "tenantId")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult resetSystemTenantUserPassword(ResetSystemTenantUserPasswordReq req) {
        //租户id
        String tenantId = req.getTenantId();
        //查询租户
        SystemTenant systemTenantOld = systemTenantMapper.selectByPrimaryKey(tenantId);
        if (systemTenantOld==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //查询租户的登录账号
        SystemUser systemUserOld = systemUserMapper.selectByPrimaryKey(tenantId);
        if (systemUserOld==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        SystemUser systemUser = new SystemUser();
        systemUser.setUserId(tenantId);
        systemUser.setPassword(MD5Util.getMD532(MD5Util.getMD532(req.getPassword())));
        systemUserMapper.updateByPrimaryKeySelective(systemUser);
        //密码修改了，强制踢出该用户的所有在线会话
        loginUserTokenCache.kickOutOnlineUserByUserId(tenantId);
        return ServiceResult.ok(tenantId);
    }


    /**
     * 批量插入功能菜单授权
     * @param tenantId
     * @param menuIdList
     */
    private void batchInsertSystemTenantMenuList(String tenantId,List<String> menuIdList){
        //清空功能权限
        deleteSystemTenantMenuByTenantId(tenantId);
        if (StringUtils.isBlank(tenantId) || menuIdList==null){
            //删除租户下面所有角色菜单关系
            deleteSystemRoleMenuByTenantId(tenantId);
            return;
        }
        //判断传过来的菜单Id是否真实有效
        //根据集合查询有效的Id
        List<String> menuIds = systemMenuMapper.queryMenuIdListBySystemMenuIdList(menuIdList);
        if (menuIds == null || menuIds.size() == 0) {
            //删除租户下面所有角色菜单关系
            deleteSystemRoleMenuByTenantId(tenantId);
            return;
        }
        //批量插入菜单ids
        List<SystemTenantMenu> systemTenantMenuList = new ArrayList<SystemTenantMenu>();
        for (String menuId : menuIds) {
            SystemTenantMenu tenantMenu = new SystemTenantMenu();
            tenantMenu.setId(UUIDUtils.getUUID32());
            tenantMenu.setMenuId(menuId);
            tenantMenu.setTenantId(tenantId);
            systemTenantMenuList.add(tenantMenu);
        }
        //插入新的权限
        systemTenantMenuMapper.batchInsertListUseAllCols(systemTenantMenuList);
        //全局改变当前租户下创建所有角色的关联菜单表，同步变动
        systemRoleMenuMapper.deleteSystemRoleMenuNotMenuIdListByTenantId(tenantId,menuIds);
    }

    /**
     * 处理返回值的数据字典
     * @param res
     */
    private void setHandleSystemTenantDictNameColor(QuerySystemTenantPageRes res) {
        if (res==null){
            return;
        }
        SystemDict dictStatus = systemDictCache.getSystemDictByDictCode(res.getStatusCode());
        res.setStatusName(dictStatus.getDictName());
        res.setStatusColor(dictStatus.getDictColor());
    }


    /**
     * 判断租户名是否存在
     */
    private void isExistTenantName(String tenantName) {
        if (StringUtils.isBlank(tenantName)){
            throw new DuoJuHeException(ErrorCodes.TENANT_NAME_EXIST);
        }
        Example example = new Example(SystemTenant.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("tenantName", tenantName);
        if (systemTenantMapper.selectByExample(example).size() > 0) {
            throw new DuoJuHeException(ErrorCodes.TENANT_NAME_EXIST);
        }
    }

    /**
     * 判断登录名是否存在
     */
    private void isExistUserLoginName(String loginName) {
        if (StringUtils.isBlank(loginName)){
            throw new DuoJuHeException(ErrorCodes.USER_LOGIN_NAME_EXIST);
        }
        SystemUser systemUser = systemUserMapper.querySystemUserByLoginName(loginName);
        if (systemUser != null) {
            throw new DuoJuHeException(ErrorCodes.USER_LOGIN_NAME_EXIST);
        }
    }


    /**
     * 判断手机号码是否存在
     */
    private void isExistUserMobileNumber(String mobileNumber) {
        if (StringUtils.isBlank(mobileNumber)){
            throw new DuoJuHeException(ErrorCodes.MOBILE_NUMBER_EXIST);
        }
        SystemUser systemUser = systemUserMapper.querySystemUserByMobileNumber(mobileNumber);
        if (systemUser != null) {
            throw new DuoJuHeException(ErrorCodes.MOBILE_NUMBER_EXIST);
        }
    }


    /**
     * 根据租户Id删除菜单绑定菜单关系
     */
    private void deleteSystemTenantMenuByTenantId(String tenantId) {
        if (StringUtils.isBlank(tenantId)){
            return;
        }
        SystemTenantMenu tenantMenu = new SystemTenantMenu();
        tenantMenu.setTenantId(tenantId);
        systemTenantMenuMapper.delete(tenantMenu);
    }


    /**
     * 根据租户Id删除角色绑定菜单绑定关系
     */
    private void deleteSystemRoleMenuByTenantId(String tenantId) {
        if (StringUtils.isBlank(tenantId)){
            return;
        }
        SystemRoleMenu roleMenu = new SystemRoleMenu();
        roleMenu.setTenantId(tenantId);
        systemRoleMenuMapper.delete(roleMenu);
    }
}
